/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.iec.edp.caf.rpc.api.support;

import io.iec.edp.caf.rpc.api.channel.RpcAbstractChannel;
import io.iec.edp.caf.rpc.api.channel.RpcChannel;
import io.iec.edp.caf.rpc.api.common.RpcChannelType;
import lombok.SneakyThrows;
import lombok.var;

import java.net.URL;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.ServiceLoader;
import java.util.concurrent.ConcurrentHashMap;

public class RpcChannelFactory {
    /**
     * 序列化器缓存
     */
    private static final Map<String, Class> rpcChannelMap = new ConcurrentHashMap<>();

    /**
     * All RpcChannel extend should in /server/runtime/libs
     */
    static {
        ServiceLoader<RpcChannel> operations = ServiceLoader.load(RpcChannel.class);

        for (RpcChannel rpcChannel : operations) {
            RpcAbstractChannel operation = (RpcAbstractChannel) rpcChannel;
            registerRpcChannel(operation.channelType(), operation.getClass());
        }
    }

    @SneakyThrows
    public static RpcAbstractChannel buildChannelServer(RpcChannelType type){
        if(type==null){
            type = RpcChannelType.GRPC;
        }
        var clazz = rpcChannelMap.get(type.getValue());
        if(clazz!=null){
            return (RpcAbstractChannel)clazz.newInstance();
        }else{
            return null;
        }

    }


    @SneakyThrows
    public static RpcChannel buildChannelClient(String msu, RpcChannelType type, HashMap<String, String> context){
        String addr;
        if(type==null){
            type = RpcChannelType.GRPC;
        }
        var clazz = rpcChannelMap.get(type.getValue());
        if(clazz==null) return null;

        var rpc = (RpcAbstractChannel)clazz.newInstance();
        addr = rpc.serviceDiscover(msu);
        if(addr==null) return null;

        URL url = new URL(addr);
        String host = url.getHost();
        int port = url.getPort();

        return rpc.buildChannel(host,port);
    }

    @SneakyThrows
    public static RpcChannel buildChannelClient(String msu, RpcChannelType type, String filterType, HashMap<String, String> context){
        String addr;
        if(type==null){
            type = RpcChannelType.GRPC;
        }
        var clazz = rpcChannelMap.get(type.getValue());
        if(clazz==null) return null;

        var rpc = (RpcAbstractChannel)clazz.newInstance();
        addr = rpc.serviceDiscover(msu);
        if(addr==null) return null;

        URL url = new URL(addr);
        String host = url.getHost();
        int port = url.getPort();

        return rpc.buildChannel(host,port,filterType);
    }


    protected static void registerRpcChannel(String typeKey, Class serialization) {
        if (!rpcChannelMap.containsKey(typeKey)) {
            rpcChannelMap.put(typeKey, serialization);
        } else {
            rpcChannelMap.remove(typeKey);
            rpcChannelMap.put(typeKey, serialization);
        }
    }
}
